
#include <GL/glu.h>
#include "glDrawFunctions.h"

//~ enum {
   //~ POINTS=0x01, WIREFRAME=0x02, HIDDENLINES=0x04, FLATLINES=0x08, 
   //~ FLAT=0x10, SMOOTH=0x20, TRANSPARENCY=0x40, RIGGING=0x80,
   //~ SKINNING=0x100, RIGGINGEDGES=0x200
   //~ };
   
float r[10]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
float g[10]={0.9,0.1,0.8,0.2,0.7,0.3,0.6,0.2,0.5,0.1};
float b[10]={0.5,0.4,0.3,0.2,0.1,0.6,0.7,0.8,0.9,0.0};

vector<Point3> colores;

void glDrawModel(Mesh *model, int meshrendermode_mask) {
   
   if (meshrendermode_mask & POINTS) {
      glPointSize(1.0);
      glDrawElements(GL_POINTS, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
   }
   else if (meshrendermode_mask & WIREFRAME) {
      glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
      glLineWidth(1.0);
      glDisable(GL_CULL_FACE);
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glPopAttrib();
   }
   else if (meshrendermode_mask & HIDDENLINES) {
      glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
      glLineWidth(1.0);
      glEnable(GL_CULL_FACE);
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glPopAttrib();
   }
   else if (meshrendermode_mask & FLATLINES) {
      glEnable(GL_POLYGON_OFFSET_FILL);
      glPolygonOffset(1,1);
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glDisable(GL_POLYGON_OFFSET_FILL);
      
      glColor4f(0.1,0.1,0.1,1.0);
      glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_LINE_BIT | GL_LIGHTING_BIT);
      glLineWidth(1.0);
      glEnable(GL_CULL_FACE);
      glDisable(GL_LIGHTING);
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glPopAttrib();
   }
   else if (meshrendermode_mask & FLAT) {
      glEnable(GL_POLYGON_OFFSET_FILL);
      glPolygonOffset(1,1);
      glShadeModel(GL_FLAT);
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glShadeModel(GL_SMOOTH);
      glDisable(GL_POLYGON_OFFSET_FILL);
   }
   else if (meshrendermode_mask & SMOOTH) {
      glEnable(GL_POLYGON_OFFSET_FILL);
      glPolygonOffset(1,1);
      glDrawElements(GL_TRIANGLES, 3*model->nfaces(), GL_UNSIGNED_INT, &model->faces[0]);
      glDisable(GL_POLYGON_OFFSET_FILL);
   }
}

void glDrawRiggingSkinning(Mesh *model, int mode_mask, bool usingbones) {
   
   if (mode_mask & RIGGING) {
      glDrawRigging(model);
   }
   else if (mode_mask & SKINNING) {
      glDrawSkinning(model);
   }
   else if (mode_mask & RIGGINGEDGES) {
      glDrawRiggingEdges((MeshWithSkeleton *)model, usingbones);
   }
}

void glDrawRigging(Mesh *model) {
   
   if (model == 0) return;
   
   for (Facet_iterator fi = model->facets_begin(); fi != model->facets_end(); ++fi) {
      Halfedge_handle hh = fi->halfedge(), hhbegin = hh;
      glBegin(GL_POLYGON);
      do {
         int idx = hh->vertex()->rigging_group%colores.size();
         GLfloat color[4] = {colores[idx][0], colores[idx][1], colores[idx][2], 1.0f};
         glMaterialfv(GL_FRONT, GL_DIFFUSE, color);
         const Point3 &p = hh->vertex()->point();
         const Vector3 &n = hh->vertex()->normal();
         glColor4fv(color);
         glNormal3f(n[0], n[1], n[2]);
         glVertex3f(p[0], p[1], p[2]);
         hh = hh->next(); //
      } while(hh != hhbegin);
      glEnd();
   }
}

void glDrawSkinning(Mesh *model) {
   
   if (model == 0) return;
   //~ cout<<"glDrawSkinning() ... "<<endl;
   GLfloat color[4];
   for (Facet_iterator fi = model->facets_begin(); fi != model->facets_end(); ++fi) {
      Halfedge_handle hh = fi->halfedge(), hhbegin = hh;
      glBegin(GL_POLYGON);
      do {
         //~ if (hh->vertex()->joints.size() > 1 or hh->vertex()->bonesweights.size() > 1) {
         unsigned int nminusone = std::count(hh->vertex()->bonesweights.begin(), 
                                       hh->vertex()->bonesweights.end(), 1.0);
         if (nminusone != 1) {
            vector<Number> ltmp(hh->vertex()->bonesweights);
            std::sort(ltmp.begin(), ltmp.end());
            Number large = ltmp.back();
            if (large > 0.9) {
               int idx = hh->vertex()->rigging_group%colores.size();
               color[0] = colores[idx][0];
               color[1] = colores[idx][1];
               color[2] = colores[idx][2];
               color[3] = 1.0f;
            }
            else {
               color[0] = large;
               color[1] = large;
               color[2] = large;
               color[3] = 1.0f;
            }
         }
         else {
            int idx = hh->vertex()->rigging_group%colores.size();
            color[0] = colores[idx][0];
            color[1] = colores[idx][1];
            color[2] = colores[idx][2];
            color[3] = 1.0f;
         }
         glMaterialfv(GL_FRONT, GL_DIFFUSE, color);
         const Point3 &p = hh->vertex()->point();
         const Vector3 &n = hh->vertex()->normal();
         glColor4fv(color);
         glNormal3f(n[0], n[1], n[2]);
         glVertex3f(p[0], p[1], p[2]);
         hh = hh->next(); // 
      } while(hh != hhbegin);
      glEnd();
   }
}

void GLdrawVerticesForSelection(Mesh *shape) {
   
   if (shape == 0) return;
   const unsigned &nverticesx3 = shape->nvertices()*3;
   glDisable(GL_LIGHTING);
   for (unsigned iv=0, i=0; iv<nverticesx3; iv+=3, i++) {
      const Point3 &p = shape->getVertexPosition(i);
      glPushName(i);
         glBegin(GL_POINTS);
         glVertex3f (p[0], p[1], p[2]);
         glEnd();
      glPopName();
   }
   glEnable(GL_LIGHTING);
}

void GLdrawFacesForSelection(Mesh *shape) {
   
   if (shape == 0) return;
   const unsigned int &nfacesx3 = shape->nfaces()*3;
   glDisable(GL_LIGHTING);
   glDisable(GL_CULL_FACE);
   
   for (unsigned fi=0, i=0; fi<nfacesx3; fi+=3, i++) {
      const unsigned int *f = &shape->faces[fi];
      const Point3 &p0 = shape->getVertexPosition(f[0]);
      const Point3 &p1 = shape->getVertexPosition(f[1]);
      const Point3 &p2 = shape->getVertexPosition(f[2]);
      
      glPushName(i);
         glBegin(GL_TRIANGLES);
         glVertex3f(p0[0], p0[1], p0[2]);
         glVertex3f(p1[0], p1[1], p1[2]);
         glVertex3f(p2[0], p2[1], p2[2]);
         glEnd();
      glPopName();
   }
   
   glEnable(GL_CULL_FACE);
   glEnable(GL_LIGHTING);
}

void glDrawModel(Mesh *shape) {
   
   if (shape == 0) return;
   
   glBegin(GL_TRIANGLES);
   for (unsigned int i=0; i<shape->nfaces(); ++i) {
      const unsigned int *f = &shape->faces[i*3];
      
      const Point3 &p0 = shape->getVertexPosition(f[0]);
      const Point3 &p1 = shape->getVertexPosition(f[1]);
      const Point3 &p2 = shape->getVertexPosition(f[2]);
      
      const Vector3 &n0 = shape->getVertexNormal(f[0]);
      const Vector3 &n1 = shape->getVertexNormal(f[1]);
      const Vector3 &n2 = shape->getVertexNormal(f[2]);
      
      glNormal3f(n0[0], n0[1], n0[2]);
      glVertex3f(p0[0], p0[1], p0[2]);
      glNormal3f(n1[0], n1[1], n1[2]);
      glVertex3f(p1[0], p1[1], p1[2]);
      glNormal3f(n2[0], n2[1], n2[2]);
      glVertex3f(p2[0], p2[1], p2[2]);
   }
   glEnd();
}

void GLdrawVerticesForSelection(const Skeleton *skeleton) {
   
   glDisable(GL_LIGHTING);
   glPointSize(10.0);
   for (unsigned int i=0; i<skeleton->nJoints(); ++i) {
      glPushName(i);
         glBegin(GL_POINTS);
         const Point3 &p = skeleton->getJointPosition(i);
         glVertex3f(p[0], p[1], p[2]);
         glEnd();
      glPopName();
   }
   glEnable(GL_LIGHTING);
}

void GLdrawBonesForSelection(const Skeleton *skeleton) {
   
   glDisable(GL_LIGHTING);
   glLineWidth(5.0);
   for (unsigned int i=0; i<skeleton->nBones(); ++i) {
      const Bone &b = skeleton->getBone(i);
      if (b.second == -1) continue;
      const Point3 &p0 = skeleton->getJointPosition(b.first);
      const Point3 &p1 = skeleton->getJointPosition(b.second);
      glPushName(i);
      glBegin(GL_LINES);
      glVertex3f(p0[0], p0[1], p0[2]);
      glVertex3f(p1[0], p1[1], p1[2]);
      glEnd();
      glPopName();
   }
   glEnable(GL_LIGHTING);
}

void glDrawPositions(const Constraints &c) {
   
   glDisable(GL_LIGHTING);
   glBegin(GL_POINTS);
   for (unsigned i=0; i<c.size(); ++i) {
      const Point3 &p = c.getPosition(i);
      glVertex3f(p[0], p[1], p[2]);
   }
   glEnd();
   glEnable(GL_LIGHTING);
   glPointSize(1.0);
}

/// Draws the positions of constraints 
void glDrawCentroids(const vector<Vector3> &centroids) {
   
   glDisable(GL_LIGHTING);
   glBegin(GL_POINTS);
   for (unsigned i=0; i<centroids.size(); ++i) {
      const Vector3 &c = centroids[i];
      glVertex3f(c[0], c[1], c[2]);
   }
   glEnd();
   glEnable(GL_LIGHTING);
   glPointSize(1.0);
}

void glDrawForSelectionTrihedron(const Constraints &c) {
   
   glPointSize(20.0);
   for (unsigned i=0; i<c.size(); i+=4) {
      glPushName(i);
      glBegin(GL_POINTS);
      const Point3 &p = c.getPosition(i);
      glVertex3f(p[0], p[1], p[2]);
      glEnd();
      glPopName();
   }
   glPointSize(1.0);
}

void glDrawForSelection(const Constraints &c) {
   
   for (unsigned i=0; i<c.size(); ++i) {
      glPushName(i);
      glBegin(GL_POINTS);
      const Point3 &p = c.getPosition(i);
      glVertex3f(p[0], p[1], p[2]);
      glEnd();
      glPopName();
   }
}

void glDrawSkel(const Skeleton *s) {
   
   if (s == 0) return;
   
   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT | GL_LINE_BIT | GL_POINT_BIT);
   glDisable(GL_LIGHTING);
   glEnable(GL_LINE_SMOOTH);
   glEnable(GL_POINT_SMOOTH);
   glEnable(GL_BLEND);
   
   glLineWidth(5.0);
   glBegin(GL_LINES);
   glColor4f(0.5,0.0,0.0,0.8);
   for (unsigned int i=0; i<s->nBones(); ++i) {
      const Bone &b = s->getBone(i);
      if (b.second == -1) continue;
      const Point3 &p0 = s->getJointPosition(b.first);
      const Point3 &p1 = s->getJointPosition(b.second);
      glColor4f(1.0,0.0,0.0,1.0);
      glVertex3f(p0[0], p0[1], p0[2]);
      glColor4f(0.0,0.0,1.0,1.0);
      glVertex3f(p1[0], p1[1], p1[2]);
   }
   glEnd();
   
   glPointSize(14.0);
   glBegin(GL_POINTS);
   glColor4f(0.7,0.7,0.2,0.8);
   for (unsigned int i=0; i<s->nJoints(); ++i) {
      const Point3 &p = s->getJointPosition(i);
      glVertex3f(p[0], p[1], p[2]);
   }
   glEnd();
   
   glPopAttrib();
}

void drawOneJointANDitsVertices(MeshWithSkeleton *model, unsigned int idjoint) {
   
   if (model == 0) return;
   if (model->skeleton == 0) return;
   if (idjoint>=model->nJoints()) return;
   if (model->skeleton->joints.empty()) return;
      
   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_POINT_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT);
   glDisable(GL_LIGHTING);
   glEnable(GL_POINT_SMOOTH);
   glEnable(GL_BLEND);
   glEnable(GL_CULL_FACE);
   //~ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   
   cout<<"idjoint: "<<idjoint<<endl;
   
   //~ glPointSize(MyOpenGLWidget::pointSize*2);
   glPointSize(15);
   glBegin(GL_POINTS);
   const Point3 &pj = model->skeleton->joints[idjoint];
   glColor4f(0.0, 1.0, 0.0, 1.0);
   glVertex3f(pj[0], pj[1], pj[2]);
   glEnd();
   
   //~ glPointSize(MyOpenGLWidget::pointSize);
   glPointSize(10);
   glBegin(GL_POINTS);
   Vertex_iterator vi = model->vertices_begin();
   while (vi != model->vertices_end()) {
      const int &i = vi->rigging_group;
      if (i == idjoint) {
         const Number &w = vi->jointsweights[i];
         const Point3 &p = vi->point();
         
         glColor4f(1.0, 0.0, 0.0, 1.0);
         //~ if (i==0)   glColor4f(1.0, 0.0, 0.0, 1.0);
         //~ else        glColor4f(1.0*w, 0.5, 1.0*w, 0.8);
         
         glVertex3f(p[0], p[1], p[2]);
      }
      ++vi;
   }
   
   //~ while (vi != model->vertices_end()) {
      //~ if (vi->rigging_group == idjoint) {
         //~ const Number *p = &model->vpositions[vi->id()];
         //~ glVertex3f(p[0], p[1], p[2]);
      //~ }
      //~ ++vi;
   //~ }
   
   glEnd();
   glPopAttrib();
}

void drawOneJointANDitsVertice(MeshWithSkeleton *model, unsigned int idjoint) {
   
   if (model == 0) return;
   if (model->skeleton == 0) return;
   if (idjoint>=model->nJoints()) return;
   if (model->skeleton->joints.empty()) return;
      
   //~ cout<<"drawOneJointANDitsVertice()"<<endl;
      
   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_POINT_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT);
   glDisable(GL_LIGHTING);
   glEnable(GL_POINT_SMOOTH);
   glEnable(GL_BLEND);
   glEnable(GL_CULL_FACE);
   //~ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   
   //~ glPointSize(MyOpenGLWidget::pointSize*2);
   glPointSize(15);
   glBegin(GL_POINTS);
   const Point3 &pj = model->skeleton->joints[idjoint];
   glColor4f(0.0, 0.0, 1.0, 1.0);
   glVertex3f(pj[0], pj[1], pj[2]);
   glEnd();
   
   //~ glPointSize(MyOpenGLWidget::pointSize);
   glPointSize(15);
   glColor4f(0.0, 1.0, 0.0, 1.0);
   glBegin(GL_POINTS);
   Vertex_iterator vi = model->vertices_begin();
   while (vi != model->vertices_end()) {
//      if ((not vi->joints.empty()) and vi->joints[0] == idjoint) {
      if (vi->rigging_group == idjoint) {
         const Point3 &p = vi->point();
         glVertex3f(p[0], p[1], p[2]);
      }
      ++vi;
   }
   glEnd();
   glPopAttrib();
}

void drawOneMeshVertexANDitsJoints(MeshWithSkeleton *model, unsigned int idvertex) {
   
   if (model == 0) return;
   if (idvertex >= model->nvertices()) return;
   
   Vertex_iterator vi = model->vertices_begin();
   std::advance(vi,idvertex);
   const Point3 &pv = vi->point();
   
   cout<<"idvertex: "<<idvertex<<endl;
   glDisable(GL_LIGHTING);
   glEnable(GL_LINE_STIPPLE);
   glLineStipple(1, 0x00FF);
   glLineWidth(2.5);
   glBegin(GL_LINES);
   /// caso para joints
   //~ for (unsigned int i=0; i<vi->joints.size(); ++i) {
      //~ const int &j = vi->joints[i];
      //~ const float &w = vi->jointsweights[i];
      //~ const Point3 &p = model->skeleton->joints[j];
      //~ glColor4f(1.0*w, 0.0, 1.0*w, 1.0);
      //~ glVertex3f(pv[0], pv[1], pv[2]);
      //~ glVertex3f(p[0], p[1], p[2]);
   //~ }
   /// caso para bones
   for (unsigned int i=0; i<vi->bonesweights.size(); ++i) {
      if (not vi->bonesweights[i] > 0) continue;
      const Bone &bo = model->skeleton->bones[i];
      const float &w = vi->bonesweights[i];
      const Point3 &a = model->skeleton->joints[bo.first];
      const Point3 &b = model->skeleton->joints[bo.second];
      glColor4f(1.0*w, 0.0, 1.0*w, 1.0);
      glVertex3f(pv[0], pv[1], pv[2]);
      glVertex3f((a[0]+b[0])*0.5, (a[1]+b[1])*0.5, (a[2]+b[2])*0.5);
      cout<<"   bone: "<<i<<" peso: "<<w<<endl;
   }
   glEnd();
   glDisable(GL_LINE_STIPPLE);
   
   glDisable(GL_LIGHTING);
}

void drawOneMeshVertexANDitsJoint(MeshWithSkeleton *model, unsigned int idvertex) {
   
   if (model == 0) return;
   if (idvertex>=model->nvertices()) return;
   
   Vertex_iterator vi = model->vertices_begin();
   std::advance(vi,idvertex);
   const Point3 &pv = vi->point();
   const Vector3 &n = vi->normal();
   
   //
   glDisable(GL_LIGHTING);
   glEnable(GL_LINE_STIPPLE);
   glLineStipple(1, 0x00FF);
   glLineWidth(3.5);
   glBegin(GL_LINES);
   const int &j = vi->rigging_group;
   const float &w = vi->jointsweights[0];
   const Point3 &p = model->skeleton->joints[j];
      glColor4f(1.0, 0.0, 0.0, 1.0);
      glVertex3f(pv[0], pv[1], pv[2]);
      glVertex3f(p[0], p[1], p[2]);
   glEnd();
   glDisable(GL_LINE_STIPPLE);
   
   glDisable(GL_LIGHTING);
}

void glDrawRiggingEdges(MeshWithSkeleton *model, bool usingbones) {
   
   if (model == 0) return;
   if (model->skeleton == 0) return;
   
   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_POINT_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT);
   glDisable(GL_LIGHTING);
   glEnable(GL_POINT_SMOOTH);
   glEnable(GL_BLEND);
   glEnable(GL_CULL_FACE);
   
   glColor4f(0.8, 0.0, 0.0, 1.0);
   glLineWidth(0.5);
   glBegin(GL_LINES);
   Vertex_iterator vi = model->vertices_begin();
   while (vi != model->vertices_end()) {
      const Point3 &pv = vi->point();
      const int &j = vi->rigging_group;
      
      if (usingbones) {
         if (j==-1) {
            glVertex3f(pv[0], pv[1], pv[2]);
            glVertex3f(0, 0, 0);
         }
         else {
            const Bone &b = model->skeleton->bones[j];
            const Point3 &p = model->skeleton->joints[b.first];
            const Point3 &q = model->skeleton->joints[b.second];
            glVertex3f(pv[0], pv[1], pv[2]);
            glVertex3f((p[0]+q[0])*0.5, (p[1]+q[1])*0.5, (p[2]+q[2])*0.5);
         }
      }
      else {
         if (j == -1) { ++vi; continue; }
         assert(j != -1 and "rigging group -1");
         assert(j < model->skeleton->nJoints() and " j > nJoints ");
         if (j >= model->skeleton->nJoints()) cout<<"j :::: "<<j<<endl;
         const Point3 &p = model->skeleton->joints[j];
         glVertex3f(pv[0], pv[1], pv[2]);
         glVertex3f(p[0], p[1], p[2]);
      }
      ++vi;
   }
   glEnd();
   glPopAttrib();
   
   //~ glColor4f(0.0, 1.0, 0.0, 1.0);
   //~ vi = model->vertices_begin();
   //~ Vertex_iterator vini = model->vertices_begin();
   //~ while (vi != model->vertices_end()) {
      //~ const int &i = vi->_vertex_parent;
      //~ if (i!=-1) cout<<" i: "<<i<<endl;
      //~ if (i != -1) {
         //~ const Point3 &p = vi->point();
         //~ const Point3 &q = vini[i].point();
         //~ glBegin(GL_POINTS);
         //~ glVertex3f(p[0], p[1], p[2]);
         //~ glVertex3f(q[0], q[1], q[2]);
         //~ glEnd();
      //~ }
      //~ ++vi;
   //~ }
}

/// drawing the 3D cursor   
void drawCursor3D(const Point3 &c, float sf) {
   
   glDisable(GL_LIGHTING);
   glColor4f(1.0,0.5,0.0,1.0);
   glLineWidth(1.0);
   
   glBegin(GL_LINE_STRIP);
   Vector3 V(-1,0,0); Vector3 uV(0,1,0); /// V = crossproduct(Vector3(0,0,1),uV)
   for (float t=0; t<2.0*3.2; t+=0.1) {
      Point3 p = c + sf*cos(t)*uV + sf*sin(t)*V;
      glVertex3f(p[0], p[1], p[2]);
   }
   glEnd();
   
   Point3 p0 = c + Vector3(1,0,0)*0.5*sf;
   Point3 p1 = c + Vector3(1,0,0)*1.5*sf;
   Point3 p2 = c + Vector3(0,1,0)*0.5*sf;
   Point3 p3 = c + Vector3(0,1,0)*1.5*sf;
   Point3 p4 = c + Vector3(-1,0,0)*0.5*sf;
   Point3 p5 = c + Vector3(-1,0,0)*1.5*sf;
   Point3 p6 = c + Vector3(0,-1,0)*0.5*sf;
   Point3 p7 = c + Vector3(0,-1,0)*1.5*sf;
   
   glColor4f(1.0,0.0,0.0,1.0);
   glBegin(GL_LINES);
   glVertex3f(p0[0], p0[1], p0[2]);
   glVertex3f(p1[0], p1[1], p1[2]);
   glVertex3f(p2[0], p2[1], p2[2]);
   glVertex3f(p3[0], p3[1], p3[2]);
   glVertex3f(p4[0], p4[1], p4[2]);
   glVertex3f(p5[0], p5[1], p5[2]);
   glVertex3f(p6[0], p6[1], p6[2]);
   glVertex3f(p7[0], p7[1], p7[2]);
   glEnd();
   
   glEnable(GL_LIGHTING);
}

void glDrawRings(list<list<Halfedge_handle> > &rings, Mesh *model) {
   
   glDisable(GL_LIGHTING);
   glColor4f(0.5,0.0,0.5,1.0);
   glPointSize(10);
   
   glBegin(GL_POINTS);
   list<list<Halfedge_handle> >::iterator it = rings.begin();
   while(it != rings.end()) {
      list<Halfedge_handle> &ring = *it++;
      list<Halfedge_handle>::iterator i = ring.begin();
      while(i != ring.end()) {
         Halfedge_handle &h = *i++;
         Point3 p = model->getVertexPosition(h->vertex());
         glVertex3f(p[0], p[1], p[2]);
      }
   }
   glEnd();
   
   glEnable(GL_LIGHTING);
   glPointSize(1);
}

void generateColors() {
   
   colores.reserve(300);
   list<Point3> cores;
   float step=0.2; bool flag = true;
   for (float r=0.0; r<=1.0; r+=step) 
      for (float g=1.0; g>=0.0; g-=step) 
         for (float b=0.0; b<=1.0; b+=step) {
            //~ if (flag) {
               //~ cores.push_back(Point3(r,g,b));
               //~ cores.push_back(Point3(b,r,g));
               //~ cores.push_back(Point3(g,b,r));
            //~ }
            //~ else {
               //~ cores.push_front(Point3(r,g,b));
               //~ cores.push_front(Point3(b,r,g));
               //~ cores.push_front(Point3(g,b,r));
            //~ }
            
            if (flag) cores.push_back(Point3(r,g,b));
            else      cores.push_front(Point3(b,r,g));
            flag = not flag;
         }
   
   colores.push_back(Point3(1.0,1.0,0.0));
   colores.push_back(Point3(1.0,0.0,1.0));
   colores.push_back(Point3(0.0,1.0,1.0));
   
   colores.push_back(Point3(1.0,0.5,0.0));
   colores.push_back(Point3(0.0,0.25,0.0));
   colores.push_back(Point3(1.0,0.0,0.5));
   colores.push_back(Point3(0.25,0.0,0.0));
   colores.push_back(Point3(0.0,1.0,0.5));
   colores.push_back(Point3(0.0,0.0,0.25));
   
   colores.push_back(Point3(0.5,1.0,0.0));
   colores.push_back(Point3(0.0,0.5,1.0));
   colores.push_back(Point3(0.5,0.0,1.0));
   
   colores.push_back(Point3(1.0,0.0,0.0));
   colores.push_back(Point3(0.0,1.0,0.0));
   colores.push_back(Point3(0.0,0.0,1.0));
   
   colores.push_back(Point3(0.5,0.0,0.0));
   colores.push_back(Point3(0.0,0.5,0.0));
   colores.push_back(Point3(0.0,0.0,0.5));
   colores.push_back(Point3(0.5,0.5,0.0));
   colores.push_back(Point3(0.5,0.0,0.5));
   colores.push_back(Point3(0.0,0.5,0.5));
   
   colores.push_back(Point3(0.75,0.75,0.0));
   colores.push_back(Point3(0.75,0.0,0.75));
   colores.push_back(Point3(0.0,0.75,0.75));
   
   colores.insert(colores.end(), cores.begin(), cores.end());
}

void glDrawPosesPaths(std::vector<std::vector<Vector> > &poses, Constraints &constraints) {
   
   if (poses.empty()) return;
   if (constraints.empty()) return;
   
   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT | GL_LINE_BIT | GL_POINT_BIT);
   glDisable(GL_LIGHTING);
   glEnable(GL_LINE_SMOOTH);
   glEnable(GL_POINT_SMOOTH);
   glEnable(GL_BLEND);
   
   glLineWidth(1.0);
   for (unsigned int j=0; j<constraints.size(); ++j) {
      glBegin(GL_LINE_STRIP);
      glColor4f(0.1,0.1,0.1,1.0);
      Point3 p = constraints.getPosition(j);
      glVertex3f(p[0], p[1], p[2]);
      for (unsigned int i=0; i<poses.size(); ++i) {
         const Vector &v = poses[i][j];
         p = p + Vector3(v[0], v[1], v[2]);
         glVertex3f(p[0], p[1], p[2]);
      }
      glEnd();
   }
   
   glPointSize(4.0);
   for (unsigned int j=0; j<constraints.size(); ++j) {
      glBegin(GL_POINTS);
      glColor4f(0.4,0.4,0.4,1.0);
      Point3 p = constraints.getPosition(j);
      glVertex3f(p[0], p[1], p[2]);
      for (unsigned int i=0; i<poses.size(); ++i) {
         const Vector &v = poses[i][j];
         p = p + Vector3(v[0], v[1], v[2]);
         glVertex3f(p[0], p[1], p[2]);
      }
      glEnd();
   }
   
   glPopAttrib();
}
